<template>
  <div class="relation" ref="myPage">
    <!-- 左边菜单 -->
    <div class="left-menu">
      <div class="allModels" @click="getAll()">全部模型<span>({{ options.length }})</span></div>
      <el-tree :data="fetch_Data" :render-content="renderContent" accordion :props="defaultProps"
        @node-expand="handleNodeClick" @node-collapse="hoverStyle" @node-click="hoverStyle"></el-tree>
    </div>

    <!-- 右边图谱 -->
    <div class="right-content">
      <RelationGraph ref="seeksRelationGraph" :options="userGraphOptions" :on-node-click="showNodeMenus"
        :on-line-click="onLineClick">
        <div slot="node" slot-scope="{ node }">
          <div style="
              height: 30px;
              border-radius: 50%;
              cursor: pointer;
              display: flex;
              justify-content: center;
              align-items: center;
            " @mouseover="onNodeOver(node, $event)" @mouseout="nodeSlotOut(node, $event)">
            <svg-icon style="color: #888888; width: 20px; height: 20px"
              :iconClass="node.data.icon ? node.data.icon : 'icon-question'"></svg-icon>
          </div>
          <div style="
              color: #868b97;
              font-size: 16px;
              position: absolute;
              width: 50px;
              height: 20px;
              margin-left: -10px;
              line-height: 11px;
              margin-top: 2px;
              font-size: 8px;
              text-align: center;
              transform: scale(0.8);
              background-color: transparent;
            ">
            {{ node.text }}
          </div>
        </div>
      </RelationGraph>
    </div>

    <!-- 线条关系弹窗 -->
    <el-dialog title="编辑关系" :visible.sync="dialogFormVisible">
      <el-form :model="form" label-width="100px" :rules="rules" ref="form">
        <!-- <el-form-item label="唯一编号">
          <el-input v-model="form.modelAssociationId" disabled></el-input>
        </el-form-item> -->
        <el-form-item label="源模型">
          <el-select v-model="form.sourceModelId" filterable>
            <el-option v-for="item in options" :key="item.modelId" :label="item.modelName" :value="item.modelId">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="目标模型" prop="destModelId">
          <el-select v-model="form.destModelId" filterable placeholder="请选择目标模型">
            <el-option v-for="item in options" :key="item.modelId" :label="item.modelName" :value="item.modelId">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="关联类型" prop="modelAssociationTypeId">
          <el-select v-model="form.modelAssociationTypeId" filterable placeholder="请选择关联类型">
            <el-option v-for="item in modelAssociationTypeoptions" :key="item.associationTypeUniqueIdentification"
              :label="item.name" :value="item.modelAssociationTypeId">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="form.remarks" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="editRelation('form')">确 定</el-button>
        <el-button @click="dialogFormVisible = false">取 消</el-button>
      </div>
    </el-dialog>

    <!-- 新增关系弹窗 -->
    <el-dialog title="新建关系" :visible.sync="newFormVisible">
      <el-form :model="new_form" label-width="100px" :rules="rules" ref="new_form">
        <el-form-item label="源模型">
          <el-select v-model="new_form.sourceModelId" filterable disabled>
            <el-option v-for="item in options" :key="item.modelId" :label="item.modelName" :value="item.modelId">
            </el-option>
          </el-select>
          <!-- <el-input v-model="new_form.sourceModelId" disabled></el-input> -->
        </el-form-item>
        <el-form-item label="目标模型" prop="destModelId">
          <el-select v-model="new_form.destModelId" filterable placeholder="请选择目标模型">
            <el-option v-for="item in options" :key="item.modelId" :label="item.modelName" :value="item.modelId">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="关联类型" prop="modelAssociationTypeId">
          <el-select v-model="new_form.modelAssociationTypeId" filterable placeholder="请选择关联类型">
            <el-option v-for="item in modelAssociationTypeoptions" :key="item.associationTypeUniqueIdentification"
              :label="item.name" :value="item.modelAssociationTypeId">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="new_form.remarks" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="addRelation('new_form')">确 定</el-button>

        <el-button @click="newFormVisible = false">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import RelationGraph from "relation-graph";
import {
  getModelCategoryList_Api,
  getModelList_Api,
  getAssociationTypeList_Api,
  getAddModelAssociation_Api,
  getEditModelAssociation_Api,
} from "@/api/configuration/model";
export default {
  name: "SeeksRelationGraphDemo",
  components: { RelationGraph },
  data() {
    return {
      menuData: [],
      newFormVisible: false, //新建关系弹框显示隐藏
      new_form: {
        sourceModelId: null, //源模型id
        destModelId: null, //目标模型id
        modelAssociationTypeId: null, //关联类型id
        remarks: "", //备注
      }, //新建关系表单
      dialogFormVisible: false, //编辑弹框隐藏显示
      //编辑弹框表单
      form: {
        modelAssociationId: "", //唯一编号
        sourceModelId: "", //源模型编号
        destModelId: "", //目标模型
        modelAssociationTypeId: "", //关联类型id
        remarks: null, //备注
      },
      g_loading: true,
      //图谱配置
      userGraphOptions: {
        backgrounImage: "", //图谱水印url
        backgrounImageNoRepeat: true, //只在右下角显示水印，不重复显示水印
        layouts: [
          {
            label: "手工", //布局描述
            layoutName: "fixed", //布局方式
            layoutClassName: "seeks-layout-fixed",
          },
        ],
        defaultFocusRootNode: false, //默认为根节点添加一个被选中的样式
        defaultNodeShape: 0, //默认的节点形状，0:圆形；1:矩形
        disableDragNode: false, //是否禁用图谱中节点的拖动
        allowShowMiniNameFilter: false,
        // allowShowMiniToolBar: false,
        defaultLineShape: 1, //默认的线条样式 ， 1：直线； 2：样式2
        defaultNodeColor: "#FFFFFF", //默认的节点背景颜色
        defaultNodeFontColor: "#868b97", //默认的节点文字颜色
        defaultNodeBorderColor: "#c4c4c6", //默认的节点边框颜色
        defaultNodeBorderWidth: 1, //默认的节点边框粗细（像素）
        defaultNodeWidth: 30, //默认的节点宽度
        defaultNodeHeight: 30, //默认的节点高度
        defaultJunctionPoint: "border", //默认的连线与节点接触的方式（border:边缘/ltrb:上下左右/tb:上下/lr:左右）
        defaultLineColor: "#c3cdd7", //默认的线条颜色
        defaultLineWidth: 1, //默认的线条粗细
      },
      defaultProps: {
        children: "children",
        label: "text",
      },
      //请求的数据
      fetch_Data: [],
      //模型选择菜单
      options: [],
      //关联类型列表
      modelAssociationTypeoptions: [],
      hostOptions: [],
      rules: {
        destModelId: [
          { required: true, message: "请选择目标模型", trigger: "blur" },
        ],
        modelAssociationTypeId: [
          { required: true, message: "请选择关联类型", trigger: "blur" },
        ],
      },
    };
  },
  created() {
    //获取分组模型
    this.getList();
    //获取关联类型
    this.getAssociationTypeList();
    //获取关联关系
    // this.getModelAssociationSearch()
  },
  mounted() { },
  methods: {
    renderContent(h, { node, data, store }) {//每个父节点统计子节点数量方法
      if (data.children) {
        return (
          // render-content采用jsx语法,需安装依赖转换js语法,
          //依赖1：npm install babel-plugin-transform-vue-jsx, 
          //依赖2：npm install babel-helper-vue-jsx-merge-props, 
          //依赖3：npm install babel-plugin-syntax-jsx
          <span class="custom-tree-node">
            <span>{node.label + '(' + data.children.length + ')'}</span>
          </span>
        );
      } else {
        return (
          <span class="custom-tree-node">
            <span>{node.label}</span>
          </span>
        );
      }
    },
    getAll() {
      document.querySelector('.allModels').style = "background-color:#f5f7fa;  padding: 2px; border-radius: 2px;cursor: pointer;"
      this.fetch_Data.forEach((item, index) => {
        this.fetch_Data[index].children.forEach(v => {
          v.opacity = 100
        })
        this.setGraphData()
      })
    },
    //获取分组模型数据
    async getList() {
      this.fetch_Data = [];
      let res = await getModelCategoryList_Api();
      let { code, data } = res;
      if (code == 200) {
        this.hostOptions = data
        //获取不分组模型
        this.getModels();
        data.forEach((item) => {
          const tempObj = {};
          tempObj.children = [];
          tempObj.id = item.modelCategoryId; //分组id
          tempObj.text = item.categoryName; //分类名称

          item.cgModels.forEach((v) => {
            const tempObj2 = {};
            tempObj2.id = v.modelId; //模型id
            tempObj2.text = v.modelName; //模型名称
            tempObj2.icon = v.icon; //模型图标
            if (v.cgModelAssociationList.length !== 0) {
              const toArray = []; //111
              v.cgModelAssociationList.forEach((value) => {
                tempObj2.remarks = value.remarks; //描述
                tempObj2.modelAssociationTypeId = value.modelAssociationTypeId; //模型关联类型id
                tempObj2.modelAssociationId = value.modelAssociationId; //关联id
                tempObj2.constraints = value.constraints; //约束
                if (value.destModelId !== tempObj2.id) {
                  toArray.push({ id: value.destModelId, desc: value.modelAssociationName });
                  tempObj2.to = toArray; //模型联系
                }
              });
            }
            tempObj.children.push(tempObj2);
          });
          this.fetch_Data.push(tempObj);
        });
        console.log(this.fetch_Data);
        // console.log(this.fetch_Data);
        this.setGraphData();
      }

    },
    //获取所有模型数据
    async getModels() {
      const arr = []
      this.hostOptions.forEach(ele => {
        ele.cgModels.forEach(item => {
          arr.push(item)
        })
      })
      this.options = arr
      // let res = await getModelList_Api();
      // let { code, data } = res;
      // if (code == 200) {
      //   this.options = data;
      // }
    },
    //获取关联类型数据
    async getAssociationTypeList() {
      let res = await getAssociationTypeList_Api();
      let { code, rows } = res;
      if (code == 200) {
        this.modelAssociationTypeoptions = rows;
      }
    },
    //图谱初始化
    setGraphData() {
      // 手工设置节点的坐标
      const _center = {
        x: 0,
        y: -300,
      };
      const graphData = {
        rootId: "root",
        nodes: [],
        lines: [],
      };

      let built_in_y = _center.y - 60;
      this.fetch_Data.forEach((item) => {
        item.children &&
          item.children.forEach((ele) => {
            graphData.nodes.push({
              ...ele,
              data: { icon: ele.icon },
              x: ele.built_in ? -300 : _center.x,
              y: ele.built_in ? (built_in_y += 60) : _center.y,
            });
            if (_center.x < 300) !ele.built_in && (_center.x += 60);
            else {
              _center.x = 0;
              _center.y += 100;
            }
            if (ele.to && ele.to.length)
              ele.to.forEach((to) =>
                graphData.lines.push({
                  text: to.desc,
                  from: ele.id,
                  to: to.id,
                  data: {
                    modelAssociationId: ele.modelAssociationId,
                    modelAssociationTypeId: ele.modelAssociationTypeId,
                    constraints: ele.constraints,
                    remarks: ele.remarks,
                  },
                })
              );
          });
      });
      this.$refs.seeksRelationGraph.setJsonData(
        graphData,
        (graphInstance) => { }
      );
    },
    //树形节点
    handleNodeClick(data) {
      document.querySelector('.allModels').style = "padding: 2px; border-radius: 2px;cursor: pointer;"
      this.fetch_Data.forEach((item, index) => {
        this.fetch_Data[index].children.forEach(v => {
          v.opacity = 100
        })
        if (data.id == item.id) {
          this.fetch_Data[index].children.forEach(v => {
            v.opacity = 100
          })
        }
        else if (data.id !== item.id) {
          this.fetch_Data[index].children.forEach(v => {
            v.opacity = 30
          })
        }
        this.setGraphData()
      })
    },
    hoverStyle() {
      document.querySelector('.allModels').style = "padding: 2px; border-radius: 2px;cursor: pointer;"
    },
    // 鼠标移入节点
    onNodeOver(nodeObject, $event) {
      const allLinks = this.$refs.seeksRelationGraph.getLinks();
      allLinks.forEach((link) => {
        // 还原所有样式
        link.relations.forEach((line) => {
          line.color = "#c3cdd7";
          line.fontColor = "#868b97";
          line.lineWidth = 1;
        });
      });
      // 让与{nodeObject}相关的所有连线高亮
      allLinks
        .filter(
          (link) => link.fromNode === nodeObject || link.toNode === nodeObject
        )
        .forEach((link) => {
          link.relations.forEach((line) => {
            line.data.orignColor = line.color;
            line.data.orignFontColor = line.fontColor || line.color;
            line.data.orignLineWidth = line.lineWidth || 1;
            line.color = "#409eff";
            line.fontColor = "#409eff";
            line.lineWidth = 1.5;
          });
        });
      // 有时候更改一些属性后，并不能马上同步到视图，这需要以下方法让视图强制根据数据同步到最新
      this.$refs.seeksRelationGraph.getInstance().dataUpdated();
    },
    //鼠标移出节点
    nodeSlotOut(nodeObject) {
      const allLinks = this.$refs.seeksRelationGraph.getLinks();
      allLinks.forEach((link) => {
        // 还原所有样式
        link.relations.forEach((line) => {
          line.color = "#c3cdd7";
          line.fontColor = "#869b97";
          line.lineWidth = 1;
        });
      });
      // 让与{nodeObject}相关的所有连线高亮
      allLinks
        .filter(
          (link) => link.fromNode === nodeObject || link.toNode === nodeObject
        )
        .forEach((link) => {
          link.relations.forEach((line) => {
            line.data.orignColor = line.color;
            line.data.orignFontColor = line.fontColor || line.color;
            line.data.orignLineWidth = line.lineWidth || 1;
            line.color = "#c3cdd7";
            line.fontColor = "#868b97";
            line.lineWidth = 1;
          });
        });
      // 有时候更改一些属性后，并不能马上同步到视图，这需要以下方法让视图强制根据数据同步到最新
      this.$refs.seeksRelationGraph.getInstance().dataUpdated();
    },
    // 线条点击
    onLineClick(lineObject, linkObject, $event) {
      this.dialogFormVisible = true;
      this.fetch_Data.forEach((item) => {
        item.children.forEach((ele) => {
          if (ele.id == lineObject.from) {
            //源模型id
            this.form.sourceModelId = ele.id;
          }
          if (ele.modelAssociationId == lineObject.data.modelAssociationId) {
            this.form.modelAssociationId = ele.modelAssociationId;
          }
          if (ele.remarks == lineObject.data.remarks) {
            this.form.remarks = ele.remarks;
          }
          if (ele.modelAssociationTypeId == lineObject.data.modelAssociationTypeId) {
            this.form.modelAssociationTypeId = ele.modelAssociationTypeId;
          }
          // if (ele.constraints == lineObject.data.constraints) {
          //   this.form.constraints = ele.constraints;
          // }
          ele.to?.forEach((v) => {
            if (v == lineObject.to) {
              this.form.destModelId = v;
            }
          });
        });
      });
      this.$notify({
        title: "点击连线：",
        type: "success",
        message:
          "点击了线:" +
          linkObject.fromNode.text +
          " to " +
          linkObject.toNode.text,
      });
    },
    //编辑关系
    editRelation(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          let res = await getEditModelAssociation_Api(this.form);
          let { code, msg } = res;
          if (code == 200) {
            this.$message.success(msg);
            this.getList();
            this.dialogFormVisible = false;
          } else {
            this.$message.error(msg);
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    //点击节点，显示新建关联
    showNodeMenus(nodeObject, $event) {
      // console.log(nodeObject);
      console.log(nodeObject.x, nodeObject.y);
      this.new_form = {
        sourceModelId: null, //源模型id
        destModelId: null, //目标模型id
        modelAssociationTypeId: null, //关联类型id
        remarks: "", //备注 //新建关系表单
      };
      this.new_form.sourceModelId = nodeObject.id;
      this.newFormVisible = true;
    },
    //新建关联
    addRelation(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          let res = await getAddModelAssociation_Api(this.new_form);
          let { code, msg } = res;
          if (code == 200) {
            this.$message.success(msg);
            this.getList();
            this.newFormVisible = false;
          } else {
            this.$message.error(msg);
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.allModels {
  padding: 2px;
  border-radius: 2px;
  cursor: pointer;

  &:hover {
    background-color: #f5f7fa;
  }
}

.c-node-menu-item {
  line-height: 30px;
  padding-left: 10px;
  cursor: pointer;
  color: #444444;
  font-size: 14px;
  border-top: #efefef solid 1px;
}

.c-node-menu-item:hover {
  background-color: rgba(66, 187, 66, 0.2);
}

.relation {
  height: calc(100vh - 105px);
  display: flex;
  justify-content: space-between;

  .left-menu {
    width: 15%;
    background-color: #ffffff;
    padding: 10px;
    box-sizing: border-box;
    border-right: 2px solid #e4e0e0;
  }

  .right-content {
    width: 84%;
  }
}

//线条字体大小设置
::v-deep .rel-linediv .c-rg-line-text {
  font-size: 10px;
  transform: scale(0.8);
}
</style>
